import path from 'path';
import fs from 'fs';
import JSON5 from 'json5';
import {HvigorNode, HvigorPlugin} from '@ohos/hvigor';
import {Hvigor} from '@ohos/hvigor/src/base/external/core/hvigor';
import {OhosPluginId} from "@ohos/hvigor-ohos-plugin";
import {HvigorTaskContext} from "@ohos/hvigor/src/base/vigor/task/interface/hvigor-task";
import {
    blackBackgroundGreenTextLog,
    blackBackgroundRedTextLog,
    blackBackgroundYellowTextLog,
    formatTimestamp,
    getModelTopoMap,
    printDepsMap,
    shouldSkipModule
} from "./utils";


export interface IbuildParams {
    coverVersion?: string;
    buildMode?: string;
    targetModule: string;
}

export let buildParams: IbuildParams = {buildMode: 'debug', targetModule: 'all'};


/**
 * harSdkBuildAllTools  –  har SDK包打包工具
 * @param runHvigor Hvigor实例
 */
export function harSdkBuildAllTools(runHvigor: Hvigor): HvigorPlugin {
    return {
        pluginId: 'harSdkBuildAllTools',
        apply(root: HvigorNode) {
            const toolsVersion = '1.3.2';
            blackBackgroundGreenTextLog(`========== [har SDK包打包工具] 插件版本 v${toolsVersion} ============`);
            blackBackgroundGreenTextLog('===== 该插件将会在hvigor中注册以下任务： =====');
            blackBackgroundGreenTextLog('===== printDepsMap ： 打印模块依赖拓扑图 =====');
            blackBackgroundGreenTextLog('===== harSdkBuildAll ： 构建har SDK包 任务 =====');
            blackBackgroundGreenTextLog('===== harSdkBuildAll任务包参数：[coverVersion | cv] [buildMode] [targetModule | tm]=====');
            blackBackgroundGreenTextLog('===== [coverVersion | cv] 是覆盖app.json5中的版本字符串,不传入则按照各个模块的versionName为目标生成版本 =====');
            blackBackgroundGreenTextLog('===== [buildMode] 是编译模式, debug / release 不传入或者传入非法默认按照debug模式进行,表示编译模块的模式 =====');
            blackBackgroundGreenTextLog('===== [targetModule | tm] 是目标模块,可以通过 printDepsMap 查看模块的拓扑依赖,模式是all 全部编译 =====');
            blackBackgroundGreenTextLog(`===== 处理接收的参数 ====`);
            const cv = runHvigor.getParameter().getExtParam('coverVersion') ?? runHvigor.getParameter().getExtParam('cv');
            const buildMode = runHvigor.getParameter().getExtParam('buildMode');
            const targetModule = runHvigor.getParameter().getExtParam('targetModule') ?? runHvigor.getParameter().getExtParam('tm');
            buildParams = {
                coverVersion: cv,
                buildMode: buildMode ?? 'debug',
                targetModule: targetModule ?? 'all',
            }
            blackBackgroundGreenTextLog(`===== [buildParams] : ${JSON.stringify(buildParams)} =====`);
            // 核心流程
            // publishAllHar
            //   ├─> buildHarFile
            //   │     ├─> collectVersionMap              // 新增：全局扫描 -> 生成 versions.json
            //   │     └─> <module>:assembleHarWithRewriteCollectHar
            //   │           ├─> <module>:rewriteLocalDeps  // 读取 versions.json 替换 file: -> 远程坐标
            //   │           └─> <module>:collectHarOutputs
            //   │                 └─> <module>:assembleHar   // 系统任务（含 default@PreBuild 等）
            //   │
            //   └─> pushHarToOhpm
            //         └─> buildHarFile

            // 1、向根节点注册 collectVersionMap 收集版本号任务
            blackBackgroundGreenTextLog(`====vvvv 开始进行任务注册 vvvv====`);
            blackBackgroundYellowTextLog(`==== 向主模块注册 collectVersionMap 任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'collectVersionMap',
                    run(taskContext: HvigorTaskContext) {
                        const buildTime = formatTimestamp();
                        console.log(`===== 【collectVersionMap】 获取每个模块的版本 ${buildTime} =====`);
                        const versionMap = new Map<string, string>();
                        const cv = buildParams.coverVersion;
                        if (cv) {
                            console.log(`===== 【collectVersionMap】 覆盖版本号 ${cv} =====`);
                        }
                        runHvigor.getRootNode().subNodes(sub => {
                            const pkgPath = path.join(sub.getNodePath(), 'oh-package.json5');
                            if (!fs.existsSync(pkgPath)) return;
                            try {
                                const json: any = JSON5.parse(fs.readFileSync(pkgPath, 'utf-8'));
                                const name = json?.name;
                                const ver = json?.version;
                                if (shouldSkipModule(name, buildParams.targetModule ?? 'all', modelTopoMap)) {
                                    blackBackgroundGreenTextLog(`==== 跳过模块: ${name} ====`);
                                    return;
                                }
                                if (cv) {
                                    versionMap.set(name, cv);
                                    console.log(`===== 【${name}:${cv}】版本覆盖-===== `);
                                } else {
                                    if (!name || ver) {
                                        versionMap.set(name, ver);
                                        console.log(`===== 【${name}:${ver}】 ===== `);
                                    }
                                }
                            } catch (e) {
                                console.error(`=====  获取模块${sub.getNodeName} 节点模块版本时发生错误：${e} =====`);
                            }
                        });
                        const versionObj = Object.fromEntries(versionMap);
                        const versionJson = JSON.stringify(versionObj);
                        runHvigor.getParameter().setProperty('versionMap', versionJson);
                        console.log(`===== 【collectVersionMap】 versionMapJsonStr: ${versionJson} =====`);
                        // 处理buildMode
                        runHvigor.getParameter().setProperty('buildMode', buildParams.buildMode);
                        console.log(`===== 【collectVersionMap】 buildMode: ${buildParams.buildMode} =====`);
                    }
                });
                blackBackgroundGreenTextLog(`==== 向主模块注册 collectVersionMap 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向主模块注册 collectVersionMap 错误！${e} ====`);
            }
            // 模块拓扑图
            const modelTopoMap = getModelTopoMap(runHvigor.getRootNode());

            // 2、为每个模块添加子任务
            // 模块依赖任务字符串数组
            const moduleTaskDeps: string[] = ['collectVersionMap'];
            blackBackgroundYellowTextLog(`==== 为每个模块添加子任务 ====`);
            try {
                runHvigor.getRootNode().subNodes(sub => {
                    blackBackgroundYellowTextLog(`==== 当前模块名: ${sub.getNodeName()} ====`);
                    const nodeName = sub.getNodeName();
                    const nodePkgPath = path.join(sub.getNodeDir().getPath(), 'oh-package.json5');
                    blackBackgroundYellowTextLog(`==== nodePkgPath:${nodePkgPath} ====`);
                    const content = fs.readFileSync(nodePkgPath, 'utf-8');
                    const pkgJson: any = JSON5.parse(content);
                    const nodePkgName: any = pkgJson.name;
                    if (shouldSkipModule(nodePkgName, buildParams.targetModule ?? 'all', modelTopoMap)) {
                        blackBackgroundGreenTextLog(`==== 跳过模块: ${nodeName} ====`);
                        return;
                    }
                    blackBackgroundYellowTextLog(`==== nodePkgName:${nodePkgName} ====`);
                    if (nodeName == 'entry') {
                        blackBackgroundGreenTextLog(`==== entry 模块不参与构建 ====`);
                        return;
                    }

                    if (!sub.getTaskByName('assembleHar')) {
                        console.log(`=====  模块: ${nodeName} 中没有assembleHar 任务=====`);
                        sub.getAllTasks().forEach(task => {
                            console.log(`=====  模块: ${nodeName} 中有 ${task.getName()} 任务=====`);
                        })
                    }
                    // 2、为每个模块添加 rewriteLocalDeps 任务，替换远程版本依赖
                    blackBackgroundYellowTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务=====`);
                    try {
                        sub.registerTask({
                            name: 'rewriteLocalDeps',
                            run(taskContext: HvigorTaskContext) {
                                // 获取versionMap
                                const versionMapJson = runHvigor.getParameter().getProperty('versionMap');
                                const obj = JSON.parse(versionMapJson);
                                const versionMap = new Map<string, string>(Object.entries(obj));
                                console.log(`=====  【rewriteLocalDeps】 读取到的versionMap :${JSON.stringify(versionMap)} =====`);
                                // 设置versionMap中的 version
                                if (versionMap.has(nodePkgName)) {
                                    blackBackgroundGreenTextLog(`调试模块版本pkgJson.version：${pkgJson.version},taskContext.moduleName:${nodePkgName}`)
                                    blackBackgroundGreenTextLog(`调试模块版本versionMap.get(taskContext.moduleName)：${versionMap.get(nodePkgName)}`)
                                    pkgJson.version = versionMap.get(nodePkgName);
                                }
                                if (pkgJson.dependencies && typeof pkgJson.dependencies === 'object') {
                                    for (const [depName, spec] of Object.entries<string>(pkgJson.dependencies)) {
                                        if (
                                            spec.startsWith('file:') &&
                                            !spec.trim().toLowerCase().endsWith('.har') &&
                                            !spec.trim().toLowerCase().endsWith('.hsp') &&
                                            versionMap &&
                                            versionMap.has(depName)
                                        ) {
                                            pkgJson.dependencies[depName] = versionMap.get(depName);
                                        }
                                    }
                                }
                                // 2.4 写回标准 JSON（保留双引号、无多余逗号）
                                fs.writeFileSync(nodePkgPath, JSON.stringify(pkgJson, null, 2) + '\n');
                            }
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务时发生错误：${e}=====`);
                    }

                    // 3、为每个模块添加 collectHarOutputs 任务，收集模块的har产物,移动到项目根目录下outputsdk/version_YYYYMMDD_HHmmss 目录下
                    blackBackgroundYellowTextLog(`=====  3、向模块: ${nodeName} 添加 collectHarOutputs 任务 ${sub.getNodeName()}:assembleHar=====`)
                    try {
                        sub.registerTask({
                            name: 'collectHarOutputs',
                            run(taskContext: HvigorTaskContext) {
                                // 模块目录
                                const moduleDir = taskContext.modulePath;           // 模块目录
                                const rootDir = runHvigor.getRootNode().getNodePath();        // 工程根目录
                                // 2.1 读取并解析 JSON5
                                const appJsonOpt = runHvigor.getRootNode().getContext(OhosPluginId.OHOS_APP_PLUGIN).getAppJsonOpt();
                                let version = '';
                                if (!buildParams.coverVersion) {
                                    version = appJsonOpt['app']['versionName'];
                                    console.log(`[har-sdk-build-plugin] 未设置版本号，采用app版本号：${version}`);
                                } else {
                                    version = buildParams.coverVersion;
                                }
                                // const ts = runHvigor.getParameter().getExtParam('buildTime')??formatTimestamp();
                                // 模块的 har 输出目录（hvigor 默认路径）
                                const harOutDir = path.join(moduleDir, 'build', 'default', 'outputs', 'default');
                                if (!fs.existsSync(harOutDir)) {
                                    console.error(`[collectHarOutputs] 模块 ${moduleDir} 未找到产物目录 ${harOutDir}`);
                                    return;
                                }
                                console.log(`[collectHarOutputs] 模块 ${moduleDir} 找到产物目录 ${harOutDir}`);
                                // 目标聚拢目录,合法化目标模块名
                                const targetModuleName = buildParams.targetModule.replace(/[^a-zA-Z0-9@]/g, '_');
                                const targetDir = path.join(rootDir, 'outputsdk', `${targetModuleName}_${version}_building`);
                                runHvigor.getParameter().setProperty('targetDir', targetDir);
                                fs.mkdirSync(targetDir, {recursive: true});

                                // 遍历复制
                                const files = fs.readdirSync(harOutDir).filter(f => f.endsWith('.har'));
                                if (files.length === 0) {
                                    console.error(`[collectHarOutputs] 模块 ${moduleDir} 没有 .har 产物`);
                                }
                                for (const f of files) {
                                    const src = path.join(harOutDir, f);
                                    const dst = path.join(targetDir, f);
                                    fs.copyFileSync(src, dst);
                                    console.log(`[collectHarOutputs] ${src} -> ${dst}`);
                                }
                            },
                            dependencies: [`assembleHar`]
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 collectHarOutputs 任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 collectHarOutputs 任务时发生错误：${e}=====`);
                    }

                    // 4、为每个模块添加 assembleHarWithRewriteCollectHar 聚合任务，依赖 rewriteLocalDeps 和 collectHarOutputs
                    blackBackgroundYellowTextLog(`=====  4、向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务 ${nodeName}:assembleHarWithRewriteCollectHar=====`)
                    try {
                        sub.registerTask({
                            name: 'assembleHarWithRewriteCollectHar',
                            run() {
                                console.log(`[assembleHarWithRewriteCollectHar] 模块 ${nodeName} 运行任务`);
                            },
                            dependencies: [`rewriteLocalDeps`, `collectHarOutputs`]
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务时发生错误：${e}=====`);
                    }
                    // 模块依赖字符串数组
                    moduleTaskDeps.push(`${nodeName}:assembleHarWithRewriteCollectHar`);
                });
                blackBackgroundGreenTextLog(`==== 为每个模块添加子任务成功！ ====`);
                blackBackgroundGreenTextLog(`==== 模块依赖数组：${JSON.stringify(moduleTaskDeps)} ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 为每个模块添加子任务错误！${e} ====`);
            }

            // 5、向根节点注册 buildHarFile 聚合任务，依赖 collectVersionMap 和每个模块的 assembleHarWithRewriteCollectHar 任务
            // 5.1、 构造模块
            blackBackgroundYellowTextLog(`==== 向跟节点注册buildHarFile任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'buildHarFile',
                    run() {
                        console.log(`[buildHarFile] 运行任务`);
                    },
                    dependencies: moduleTaskDeps,
                    afterRun: (taskContext: HvigorTaskContext) => {
                        const targetDir = runHvigor.getParameter().getProperty('targetDir');
                        blackBackgroundGreenTextLog(`[buildHarFile] 聚合任务完成`)
                        // 1) 取目录 & 时间戳
                        const paramSvc = runHvigor.getParameter();
                        const targetDirRaw = paramSvc.getProperty?.('targetDir') || process.env.targetDir || '';
                        if (!targetDirRaw) {
                            console.log(`[buildHarFile] 未提供 targetDir，跳过重命名`);
                            return;
                        }

                        // 共用同一批构建时间戳，若外部已设置则复用
                        const ts = `${buildParams.buildMode}_${formatTimestamp()}`;

                        // 2) 校验目录存在
                        if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
                            console.log(`[buildHarFile] 目标目录不存在或不是目录：${targetDir}`);
                            return;
                        }

                        // 3) 计算新目录名：将最后一级目录名中的 'building' 替换为时间戳
                        const parent = path.dirname(targetDir);
                        const base = path.basename(targetDir);

                        let newBase = base.replace(/building/gi, ts);
                        if (newBase === base) {
                            // 没有包含 'building'；可选择追加时间戳避免无变化
                            newBase = `${base}_${ts}`;
                        }

                        const newDir = path.join(parent, newBase);

                        // 4) 若目标已存在，附加一个短随机串避免覆盖
                        let finalDir = newDir;
                        if (fs.existsSync(finalDir)) {
                            finalDir = `${newDir}_${Math.random().toString(36).slice(2, 6)}`;
                        }

                        // 5) 执行重命名
                        try {
                            fs.renameSync(targetDir, finalDir);
                            console.log(`[buildHarFile] 重命名完成：\n  from: ${targetDir}\n  to  : ${finalDir}`);
                            // 可选：把新的路径写回扩展参数，供后续任务/日志使用
                            // taskContext.setExtParam?.('finalTargetDir', finalDir);
                        } catch (e: any) {
                            console.error(`[buildHarFile] 重命名失败：${e?.message || e}`);
                        }
                    }
                });
                blackBackgroundGreenTextLog(`==== 向跟节点注册buildHarFile任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向跟节点注册buildHarFile任务错误！${e} ====`);
            }

            // 6、向根节点注册 pushHarToOhpm 推送har包任务，依赖 buildHarFile
            blackBackgroundYellowTextLog(`==== 向根节点注册pushHarToOhpm任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'pushHarToOhpm',
                    run() {
                        console.log(`[pushHarToOhpm] 运行任务...暂未实现`);
                    },
                    dependencies: ['buildHarFile']
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册pushHarToOhpm任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册pushHarToOhpm任务错误！${e} ====`);
            }

            // 7、向节点注册 harSdkBuildAll 任务,依赖 pushHarToOhpm
            blackBackgroundYellowTextLog(`==== 向根节点注册harSdkBuildAll任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'harSdkBuildAll',
                    run() {

                    },
                    dependencies: ['pushHarToOhpm']
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册harSdkBuildAll任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册harSdkBuildAll任务错误！${e} ====`);
            }

            // 8、向根节点注册 打印模块依赖拓扑图任务：
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'printDepsMap',
                    run() {
                        // 打印模块拓扑图
                        printDepsMap(root);
                    },
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册 printDepsMap 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册 printDepsMap 任务错误！${e} ====`);
            }
        }
    }
}